/**
 *  Stream Recorder: Records RealPlayer(tm) streams as MP3s
 *  Copyright (C) 2007  David Griffiths
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

package dg.radio2ipod.view;

import dg.inx.OKCancelEditor;
import dg.inx.XMLMenuBar;
import dg.radio2ipod.BrowserLauncher;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FileDialog;
import java.awt.Point;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.ResourceBundle;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import dg.radio2ipod.Main;
import dg.radio2ipod.Util;
import dg.radio2ipod.controller.Animator;
import dg.radio2ipod.model.Settings;
import dg.radio2ipod.model.StreamList;
import dg.radio2ipod.model.Stream;
import dg.radio2ipod.model.StreamFactory;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.Font;
import java.net.MalformedURLException;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;

/**
 *
 * @author davidg
 */
public final class MainFrame extends JFrame {
    private static ResourceBundle resBundle = ResourceBundle.getBundle(
            "dg/radio2ipod/resource/strings");
    static final Font CONSOLE_FONT = new Font("courier", Font.PLAIN, 14);
    static final Font DRAG_LABEL_FONT = new Font("sans-serif", Font.PLAIN, 44);

    private JList list;
    private JTextArea console;
    private JSplitPane splitPane;
    private JScrollPane scrollConsole;
    private JLabel dragLabel;
    private JPanel content;
    private CardLayout contentCards = new CardLayout();
    private Animator splitAnimator;
    private static final double GOLDEN_RATIO = 0.61803398875;

    private StreamList streamList;

    public MainFrame() {
        super(resBundle.getString("app.name"));
        streamList = new StreamList();
        buildView();
        buildControllers();
    }

    private void buildView() {
        Settings s = Settings.getInstance();

        dragLabel = new JLabel(resBundle.getString("drag_audio"));
        dragLabel.setHorizontalAlignment(JLabel.CENTER);
        dragLabel.setVerticalAlignment(JLabel.CENTER);
        dragLabel.setFont(DRAG_LABEL_FONT);
        dragLabel.setForeground(new Color(172, 172, 172));
        dragLabel.setBackground(Color.WHITE);
        dragLabel.setOpaque(true);

        list = new JList(streamList);
        final StreamCellRenderer scr = new StreamCellRenderer();
        list.setCellRenderer(scr);
        JScrollPane scrollList = new JScrollPane(list,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);

        console = new JTextArea();
        console.setFont(CONSOLE_FONT);
        console.setLineWrap(true);
        console.setAutoscrolls(true);
        console.setEditable(false);
        scrollConsole = new JScrollPane(console,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        content = new JPanel(contentCards);
        content.add(dragLabel, "DRAGLABEL");
        content.add(scrollList, "STREAMLIST");
        contentCards.show(content, "DRAGLABEL");

        splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
                content, scrollConsole);
        splitPane.setOneTouchExpandable(true);

        getContentPane().add(splitPane, BorderLayout.CENTER);

        buildMenus();
        setBounds(s.getWindowLeft(), s.getWindowTop(),
                s.getWindowWidth(), s.getWindowHeight());
        splitPane.setDividerLocation(s.getWindowHeight());
    }

    private int progressStarts;
    public void consoleWrite(String s) {
        if ((s == null)
        || (s.length() == 0)
        || (s.indexOf("Cache fill:") != -1)
        || (s.startsWith("A:"))) {
            return;
        }
        boolean isProgress = ((s.indexOf("A:") != -1)
        && (s.indexOf("%)|") != -1));
        if (!isProgress) {
            progressStarts = console.getDocument().getLength();
            console.append(s +"\r\n");
        } else {
            console.replaceRange(s + "\r\n", progressStarts,
                    console.getDocument().getLength());
        }
        console.setCaretPosition(console.getDocument().getLength());
    }

    private void buildControllers() {
        list.addMouseListener(new MouseAdapter() {
            public void mouseReleased(final MouseEvent evt) {
                Point p = evt.getPoint();
                listClicked(p);
            }
        });
        addDnD(list, this);
        addDnD(dragLabel, this);
        console.setDragEnabled(true);
        addDnD(console, this);
        addDnD(splitPane, this);
    }

    private void listClicked(final Point p) {
        int listHeight = 45;
        int listItem = p.y / listHeight;
        int x = p.x;
        int y = p.y % listHeight;
        if (listItem < streamList.getSize()) {
            int w = list.getSize().width;
            if ((x > w - 26) && (x < w - 14)) {
                if ((y > (listHeight - 12) / 2) && (y < (listHeight
                        + 12) / 2)) {
                    streamList.remove(listItem);
                }
            }
        }
    }

    private void buildMenus() {
        XMLMenuBar menuBar = new XMLMenuBar(this,
                "/dg/radio2ipod/view/mainframeMenu.xml", resBundle);
        if (!Main.isMac()) {
            JMenu helpMenu = menuBar.getMenu("help");
            JMenuItem about = new JMenuItem(resBundle.getString("menu.about")
            + resBundle.getString("app.name"));
            about.addActionListener(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    helpAbout();
                }
            });
            helpMenu.add(about);
            JMenu fileMenu = menuBar.getMenu("file");
            JMenuItem itemExit = new JMenuItem(resBundle.getString(
                    "menu.exit"));
            itemExit.addActionListener(new ActionListener() {
                public void actionPerformed(final ActionEvent e) {
                    fileExit();
                }
            });
            fileMenu.addSeparator();
            fileMenu.add(itemExit);
        }
        setJMenuBar(menuBar);
    }

    public void saveNext() {
        this.streamList.saveNext();
    }

    public void openDocument() throws IOException {
        FileDialog chooser = new FileDialog(this, "Open Stream File",
                FileDialog.LOAD);

        chooser.setVisible(true);

        String filename = chooser.getFile();

        if (filename != null) {
            addStream(StreamFactory.getStream(new File(chooser.getDirectory(),
                    filename)));
        }
    }

    public void fileExit() {
        System.exit(0);
    }

    public void helpAbout() {
        Main.showAbout();
    }

    public void openHomepage() {
        try {
            BrowserLauncher.openURL("http://code.google.com/p/radio2ipod/");
        } catch(MalformedURLException mfue) {
            mfue.printStackTrace();
        } catch(IOException ioe) {
            ioe.printStackTrace();
        }
    }

    public void toggleConsole() {
        int div = splitPane.getDividerLocation();
        int max = splitPane.getMaximumDividerLocation();
        int min = splitPane.getMinimumDividerLocation();
        if (div > max) {
            div = max;
        }
        int diff = max - div;
        int target = max;
        if (diff < 10) {
            target = (int)(max * (1 - GOLDEN_RATIO));
        }
        if (splitAnimator == null) {
            splitAnimator = new Animator(splitPane, "dividerLocation");
            splitAnimator.setMin(min);
            splitAnimator.setMax(max);
        }
        splitAnimator.setTarget(target);
        splitAnimator.start();
    }

    public void addStream(final Stream stream) {
        stream.setImportITunes(Settings.getInstance().isImportToITunes());
        stream.setStereo(Settings.getInstance().isStereo());
        OKCancelEditor editor = new OKCancelEditor(this, "#title", stream,
                "/dg/radio2ipod/view/streamEditor.xml");
        editor.setVisible(true);
        if (!editor.isCancelled()) {
            contentCards.show(content, "STREAMLIST");
            streamList.add(stream);
            int div = splitPane.getDividerLocation();
            int diff = getSize().height - div;
            boolean consoleHidden = (diff < 100);
            if (consoleHidden) {
                toggleConsole();
            }
        }
    }

    public static void addDnD(final Component c, final MainFrame main) {
        DropTargetListener dtl = new MFDropTargetListener(main);
        DropTarget dt = new DropTarget(c, dtl);
        dt.setActive(true);
    }
}

class MFDropTargetListener implements DropTargetListener {
    private MainFrame mainframe;

    MFDropTargetListener(MainFrame mf) {
        this.mainframe = mf;
    }

    public void dragEnter(final DropTargetDragEvent dtde) {
    }
    public void dragExit(final DropTargetEvent dtde) {
    }
    public void dragOver(final DropTargetDragEvent dtde) {
    }
    public void dropActionChanged(final DropTargetDragEvent dtde) {
    }
    public void drop(final DropTargetDropEvent event) {
        try {
            Transferable transferable = event.getTransferable();
            System.out.println("transferable = " + transferable);
            if (transferable.isDataFlavorSupported(
                    DataFlavor.javaFileListFlavor)) {
                event.acceptDrop(DnDConstants.ACTION_COPY);
                final Object os = transferable.getTransferData(
                        DataFlavor.javaFileListFlavor);
                if (!(os instanceof java.util.Collection)) {
                    Util.errorMessage("Not a collection!!!!!!");
                    return;
                }
                boolean err = false;
                for (Iterator i
                        = ((java.util.Collection) os).iterator();
                i.hasNext();) {
                    File f = (File) i.next();
                    Stream s = StreamFactory.getStream(f);
                    mainframe.addStream(s);
                }
                event.getDropTargetContext().dropComplete(true);
            } else if (transferable.isDataFlavorSupported(
                    DataFlavor.stringFlavor)) {
                event.acceptDrop(DnDConstants.ACTION_COPY);

                // Modifications made by bharathch follow.The
                // modifications were made to address issue #17:
                // "Dragging new feeds from Firefox.."
                String urlString = transferable.getTransferData(
                        DataFlavor.stringFlavor).toString();
                // DnD from firefox introduces a \n followed by the
                // anchor label that appears on the page. Hence, use
                // only the substring upto the \n
                int linebreakIndex = urlString.indexOf('\n');
                String insertText = null;
                if (linebreakIndex != -1) {
                    insertText = urlString.substring(0,
                            linebreakIndex);
                } else {
                    // DnD from IE and other browsers;use the string as
                    // it is.
                    insertText = urlString;
                }
                final String it = insertText;

                // This is how the previous insertText was previously
                // obtained:
                // insertText = transferable.getTransferData(
                //                DataFlavor.stringFlavor).toString();
                // Modifications end
                (new Thread() {
                    public void run() {
                        try {
                            Stream s = StreamFactory.getStream(
                                    new URL(it));
                            mainframe.addStream(s);
                        } catch (Throwable t2) {
                            Util.errorMessage(t2.getMessage());
                            t2.printStackTrace();
                        }
                    }
                }).start();
                event.getDropTargetContext().dropComplete(true);
            } else {
                Util.errorMessage("Sorry - I can only record streams and URLs");
                event.rejectDrop();
            }
        } catch (Throwable t) {
            t.printStackTrace();
            event.rejectDrop();
        }
    }
}
